#include <iostream>
#include <boost/python.hpp>


class A
{
public:
   void f() const
   {
      std::cout << "[C++] A::f()" << std::endl;
   }
};

template<typename T>
class smart_pointer
{
public:
   smart_pointer() : obj(NULL)
   {
   }

   smart_pointer(const smart_pointer& p) : obj(p.obj)
   {
   }

   // Required for boost::python::pointee specialization to work.
   smart_pointer(T* obj_) : obj(obj_)
   {
   }

   ~smart_pointer()
   {
//      delete obj;
//      obj = NULL;
   }

   // Const correctness for these two operator overloads may be critical.
   T* operator->() const
   {
      return obj;
   }

   T& operator*() const
   {
      return *obj;
   }

   T* get() const
   {
      return obj;
   }

   smart_pointer& operator=(const smart_pointer& p)
   {
      this->obj = p.obj;
      return *this;
   }

   operator bool() const
   {
      return this->obj != NULL;
   }

   // Having this eliminates the need to specialize boost::python::pointee<T>.
//   typedef T element_type;

private:
   T* obj;
};

void func()
{
   smart_pointer<A> obj;
   obj->f();
}

smart_pointer<A> New()
{
   return smart_pointer<A>(new A());
}

void Ok(const smart_pointer<A>& a)
{
   a->f();
}

void Fail(smart_pointer<A>& a)
{
   a->f();
}

namespace boost
{

namespace python
{

template<class T> T* get_pointer(const smart_pointer<T>& p)
{
   return p.get();
}

template<class T> struct pointee< smart_pointer<T> >
{
   typedef T type;
};

}

}

using namespace boost::python;

BOOST_PYTHON_MODULE(tester)
{
   class_<A>("A", init<>())
      .def("f", &A::f)
   ;

   def("New", &New);
   def("Ok", &Ok);
   def("Fail", &Fail);

   register_ptr_to_python< smart_pointer<A> >();
}
